;; Scheduling description for HEXIN C2000 processor.
;; Copyright (C) 2013-2022 Free Software Foundation, Inc.
;;

;; This file is part of GCC.
;;
;; GCC is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published
;; by the Free Software Foundation; either version 3, or (at your
;; option) any later version.
;;
;; GCC is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
;; License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3.  If not see
;; <http://www.gnu.org/licenses/>.

(define_automaton "c2000fxu,c2000lsu,c2000vsu,c2000misc")

(define_cpu_unit "fxu0_c2000,fxu1_c2000" "c2000fxu")
(define_cpu_unit "lu0_c2000,lu1_c2000" "c2000lsu")
(define_cpu_unit "lsu0_c2000,lsu1_c2000" "c2000lsu")
(define_cpu_unit "vsu0_c2000,vsu1_c2000" "c2000vsu")
(define_cpu_unit "bpu_c2000,cru_c2000" "c2000misc")
(define_cpu_unit "du0_c2000,du1_c2000,du2_c2000,du3_c2000,du4_c2000,\
		  du5_c2000,du6_c2000"  "c2000misc")


; Dispatch group reservations
(define_reservation "DU_any_c2000"
		    "du0_c2000|du1_c2000|du2_c2000|du3_c2000|du4_c2000|\
		     du5_c2000")

; 2-way Cracked instructions go in slots 0-1
;   (can also have a second in slots 3-4 if insns are adjacent)
(define_reservation "DU_cracked_c2000"
		    "du0_c2000+du1_c2000")

; Insns that are first in group
(define_reservation "DU_first_c2000"
		    "du0_c2000")

; Insns that are first and last in group
(define_reservation "DU_both_c2000"
		    "du0_c2000+du1_c2000+du2_c2000+du3_c2000+du4_c2000+\
		     du5_c2000+du6_c2000")

; Dispatch slots are allocated in order conforming to program order.
(absence_set "du0_c2000" "du1_c2000,du2_c2000,du3_c2000,du4_c2000,\
	      du5_c2000,du6_c2000")
(absence_set "du1_c2000" "du2_c2000,du3_c2000,du4_c2000,du5_c2000,\
	      du6_c2000")
(absence_set "du2_c2000" "du3_c2000,du4_c2000,du5_c2000,du6_c2000")
(absence_set "du3_c2000" "du4_c2000,du5_c2000,du6_c2000")
(absence_set "du4_c2000" "du5_c2000,du6_c2000")
(absence_set "du5_c2000" "du6_c2000")


; Execution unit reservations
(define_reservation "FXU_c2000"
                    "fxu0_c2000|fxu1_c2000")

(define_reservation "LU_c2000"
                    "lu0_c2000|lu1_c2000")

(define_reservation "LSU_c2000"
                    "lsu0_c2000|lsu1_c2000")

(define_reservation "LU_or_LSU_c2000"
                    "lu0_c2000|lu1_c2000|lsu0_c2000|lsu1_c2000")

(define_reservation "VSU_c2000"
                    "vsu0_c2000|vsu1_c2000")


; LS Unit
(define_insn_reservation "c2000-load" 3
  (and (eq_attr "type" "load")
       (eq_attr "sign_extend" "no")
       (eq_attr "update" "no")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,LU_or_LSU_c2000")

(define_insn_reservation "c2000-load-update" 3
  (and (eq_attr "type" "load")
       (eq_attr "sign_extend" "no")
       (eq_attr "update" "yes")
       (eq_attr "cpu" "c2000"))
  "DU_cracked_c2000,LU_or_LSU_c2000+FXU_c2000")

(define_insn_reservation "c2000-load-ext" 3
  (and (eq_attr "type" "load")
       (eq_attr "sign_extend" "yes")
       (eq_attr "update" "no")
       (eq_attr "cpu" "c2000"))
  "DU_cracked_c2000,LU_or_LSU_c2000,FXU_c2000")

(define_insn_reservation "c2000-load-ext-update" 3
  (and (eq_attr "type" "load")
       (eq_attr "sign_extend" "yes")
       (eq_attr "update" "yes")
       (eq_attr "cpu" "c2000"))
  "DU_both_c2000,LU_or_LSU_c2000+FXU_c2000,FXU_c2000")

(define_insn_reservation "c2000-fpload" 5
  (and (ior (eq_attr "type" "vecload")
	    (and (eq_attr "type" "fpload")
		 (eq_attr "update" "no")))
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,LU_c2000")

(define_insn_reservation "c2000-fpload-update" 5
  (and (eq_attr "type" "fpload")
       (eq_attr "update" "yes")
       (eq_attr "cpu" "c2000"))
  "DU_cracked_c2000,LU_c2000+FXU_c2000")

(define_insn_reservation "c2000-store" 5 ; store-forwarding latency
  (and (eq_attr "type" "store")
       (not (and (eq_attr "update" "yes")
		 (eq_attr "indexed" "yes")))
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,LSU_c2000+LU_c2000")

(define_insn_reservation "c2000-store-update-indexed" 5
  (and (eq_attr "type" "store")
       (eq_attr "update" "yes")
       (eq_attr "indexed" "yes")
       (eq_attr "cpu" "c2000"))
  "DU_cracked_c2000,LSU_c2000+LU_c2000")

(define_insn_reservation "c2000-fpstore" 5
  (and (eq_attr "type" "fpstore")
       (eq_attr "update" "no")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,LSU_c2000+VSU_c2000")

(define_insn_reservation "c2000-fpstore-update" 5
  (and (eq_attr "type" "fpstore")
       (eq_attr "update" "yes")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,LSU_c2000+VSU_c2000")

(define_insn_reservation "c2000-vecstore" 5
  (and (eq_attr "type" "vecstore")
       (eq_attr "cpu" "c2000"))
  "DU_cracked_c2000,LSU_c2000+VSU_c2000")

(define_insn_reservation "c2000-larx" 3
  (and (eq_attr "type" "load_l")
       (eq_attr "cpu" "c2000"))
  "DU_both_c2000,LU_or_LSU_c2000")

(define_insn_reservation "c2000-stcx" 10
  (and (eq_attr "type" "store_c")
       (eq_attr "cpu" "c2000"))
  "DU_both_c2000,LSU_c2000+LU_c2000")

(define_insn_reservation "c2000-sync" 1
  (and (eq_attr "type" "sync,isync")
       (eq_attr "cpu" "c2000"))
  "DU_both_c2000,LSU_c2000")


; FX Unit
(define_insn_reservation "c2000-1cyc" 1
  (and (ior (eq_attr "type" "integer,insert,trap,isel")
	    (and (eq_attr "type" "add,logical,shift,exts")
		 (eq_attr "dot" "no")))
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,FXU_c2000")

; Extra cycle to LU/LSU
(define_bypass 2 "c2000-1cyc"
		 "c2000-load*,c2000-fpload*,c2000-store*,c2000-fpstore*,\
		  c2000-vecstore,c2000-larx,c2000-stcx")
;		 "c2000-load,c2000-load-update,c2000-load-ext,\
;		  c2000-load-ext-update,c2000-fpload,c2000-fpload-update,\
;		  c2000-store,c2000-store-update,c2000-store-update-indexed,\
;		  c2000-fpstore,c2000-fpstore-update,c2000-vecstore,\
;		  c2000-larx,c2000-stcx")

(define_insn_reservation "c2000-2cyc" 2
  (and (eq_attr "type" "cntlz,popcnt")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,FXU_c2000")

(define_insn_reservation "c2000-two" 2
  (and (eq_attr "type" "two")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000+DU_any_c2000,FXU_c2000,FXU_c2000")

(define_insn_reservation "c2000-three" 3
  (and (eq_attr "type" "three")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000+DU_any_c2000+DU_any_c2000,FXU_c2000,FXU_c2000,FXU_c2000")

; cmp - Normal compare insns
(define_insn_reservation "c2000-cmp" 2
  (and (eq_attr "type" "cmp")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,FXU_c2000")

; add/logical with dot : add./and./nor./etc
(define_insn_reservation "c2000-fast-compare" 2
  (and (eq_attr "type" "add,logical")
       (eq_attr "dot" "yes")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,FXU_c2000")

; exts/shift with dot : rldicl./exts./rlwinm./slwi./rlwnm./slw./etc
(define_insn_reservation "c2000-compare" 2
  (and (eq_attr "type" "shift,exts")
       (eq_attr "dot" "yes")
       (eq_attr "cpu" "c2000"))
  "DU_cracked_c2000,FXU_c2000,FXU_c2000")

; Extra cycle to LU/LSU
(define_bypass 3 "c2000-fast-compare,c2000-compare"
		 "c2000-load*,c2000-fpload*,c2000-store*,c2000-fpstore*,\
		  c2000-vecstore,c2000-larx,c2000-stcx")

; 5 cycle CR latency 
(define_bypass 5 "c2000-fast-compare,c2000-compare"
		 "c2000-crlogical,c2000-mfcr,c2000-mfcrf,c2000-branch")

(define_insn_reservation "c2000-mul" 4
  (and (eq_attr "type" "mul")
       (eq_attr "dot" "no")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,FXU_c2000")

(define_insn_reservation "c2000-mul-compare" 4
  (and (eq_attr "type" "mul")
       (eq_attr "dot" "yes")
       (eq_attr "cpu" "c2000"))
  "DU_cracked_c2000,FXU_c2000")

; Extra cycle to LU/LSU
(define_bypass 5 "c2000-mul,c2000-mul-compare"
		 "c2000-load*,c2000-fpload*,c2000-store*,c2000-fpstore*,\
		  c2000-vecstore,c2000-larx,c2000-stcx")

; 7 cycle CR latency 
(define_bypass 7 "c2000-mul,c2000-mul-compare"
		 "c2000-crlogical,c2000-mfcr,c2000-mfcrf,c2000-branch")

; FXU divides are not pipelined
(define_insn_reservation "c2000-idiv" 37
  (and (eq_attr "type" "div")
       (eq_attr "size" "32")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,fxu0_c2000*37|fxu1_c2000*37")

(define_insn_reservation "c2000-ldiv" 68
  (and (eq_attr "type" "div")
       (eq_attr "size" "64")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,fxu0_c2000*68|fxu1_c2000*68")

(define_insn_reservation "c2000-mtjmpr" 5
  (and (eq_attr "type" "mtjmpr")
       (eq_attr "cpu" "c2000"))
  "DU_first_c2000,FXU_c2000")

; Should differentiate between 1 cr field and > 1 since mtocrf is not microcode
(define_insn_reservation "c2000-mtcr" 3
  (and (eq_attr "type" "mtcr")
       (eq_attr "cpu" "c2000"))
  "DU_both_c2000,FXU_c2000")


; CR Unit
(define_insn_reservation "c2000-mfjmpr" 5
  (and (eq_attr "type" "mfjmpr")
       (eq_attr "cpu" "c2000"))
  "DU_first_c2000,cru_c2000+FXU_c2000")

(define_insn_reservation "c2000-crlogical" 3
  (and (eq_attr "type" "cr_logical")
       (eq_attr "cpu" "c2000"))
  "DU_first_c2000,cru_c2000")

(define_insn_reservation "c2000-mfcr" 5
  (and (eq_attr "type" "mfcr")
       (eq_attr "cpu" "c2000"))
  "DU_both_c2000,cru_c2000")

(define_insn_reservation "c2000-mfcrf" 3
  (and (eq_attr "type" "mfcrf")
       (eq_attr "cpu" "c2000"))
  "DU_first_c2000,cru_c2000")


; BR Unit
; Branches take dispatch slot 7, but reserve any remaining prior slots to
; prevent other insns from grabbing them once this is assigned.
(define_insn_reservation "c2000-branch" 3
  (and (eq_attr "type" "jmpreg,branch")
       (eq_attr "cpu" "c2000"))
  "(du6_c2000\
   |du5_c2000+du6_c2000\
   |du4_c2000+du5_c2000+du6_c2000\
   |du3_c2000+du4_c2000+du5_c2000+du6_c2000\
   |du2_c2000+du3_c2000+du4_c2000+du5_c2000+du6_c2000\
   |du1_c2000+du2_c2000+du3_c2000+du4_c2000+du5_c2000+du6_c2000\
   |du0_c2000+du1_c2000+du2_c2000+du3_c2000+du4_c2000+du5_c2000+\
    du6_c2000),bpu_c2000")

; Branch updating LR/CTR feeding mf[lr|ctr]
(define_bypass 4 "c2000-branch" "c2000-mfjmpr")


; VS Unit (includes FP/VSX/VMX/DFP/Crypto)
(define_insn_reservation "c2000-fp" 6
  (and (eq_attr "type" "fp,fpsimple,dmul,dfp")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

; Additional 3 cycles for any CR result
(define_bypass 9 "c2000-fp" "c2000-crlogical,c2000-mfcr*,c2000-branch")

(define_insn_reservation "c2000-fpcompare" 8
  (and (eq_attr "type" "fpcompare")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-sdiv" 27
  (and (eq_attr "type" "sdiv")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-ddiv" 33
  (and (eq_attr "type" "ddiv")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-sqrt" 32
  (and (eq_attr "type" "ssqrt")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-dsqrt" 44
  (and (eq_attr "type" "dsqrt")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-vecsimple" 2
  (and (eq_attr "type" "vecperm,vecsimple,veclogical,vecmove,veccmp,
			veccmpfx")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-vecnormal" 6
  (and (eq_attr "type" "vecfloat,vecdouble")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_bypass 7 "c2000-vecnormal"
		 "c2000-vecsimple,c2000-veccomplex,c2000-fpstore*,\
		  c2000-vecstore")

(define_insn_reservation "c2000-veccomplex" 7
  (and (eq_attr "type" "veccomplex")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-vecfdiv" 25
  (and (eq_attr "type" "vecfdiv")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-vecdiv" 31
  (and (eq_attr "type" "vecdiv")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-mtvsr" 5
  (and (eq_attr "type" "mtvsr")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-mfvsr" 6
  (and (eq_attr "type" "mfvsr")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

(define_insn_reservation "c2000-crypto" 7
  (and (eq_attr "type" "crypto")
       (eq_attr "cpu" "c2000"))
  "DU_any_c2000,VSU_c2000")

